﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using InvestmentIntelligence.TradingData.TradingDataModels;
using InvestmentIntelligence.TradingData.TradingDataTypes;

namespace InvestmentIntelligence.TradingData.Handlers.Mus
{
    public static class Mappings
    {
        private static readonly HashSet<string> TradeEntryTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            "Buy",
            "Cover",
            "Short",
            "Sell"
        };

        private static readonly HashSet<string> SellTradeEntryTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            "Short",
            "Sell"
        };

        public static TradingDataSecurityDto TradingDataSecurityDto(DataRow arg)
        {
            return new TradingDataSecurityDto
            {
                CustomIdentity = arg.Get("OriginalSourceId") ?? string.Empty,
                SecurityIdentity = arg.Get("SourceIdentity") ?? string.Empty,
                SecurityIdentityType = "CustomIdentificator",
                Isin = arg.Get("Isin"),
                Ric = arg.Get("Ric"),
                Sedol = arg.Get("Sedol"),
                Mic = string.Empty,
                SecurityName = arg.Get("Name"),
                LongName = arg.Get("LongName"),
                ParentIdentifier = arg.Get("ParentIdentifier"),
                ParentIdentifierType = IdentityType.CustomIdentificator,
                EconomicSectorName = arg.Get("EconomicSectorName"),
                EconomicSectorCode = arg.Field<int>("EconomicSectorCode"),
                IndustryGroupName = arg.Get("IndustryGroupName"),
                BusinesSectorName = "Unclassified",
                IndustryGroupCode = 0,
                BusinesSectorCode = 0,
                SecurityClass = arg.Get("SecurityClass"),
                CurrencyCode = arg.Get("CurrencyCode"),
                CountryCode = arg.Get("CountryCode"),
                CountryDescription = arg.Get("CountryDescription"),
            };
        }

        public static TradingDataFundbookDto TradingDataFundbookDto(DataRow arg)
        {
            return new TradingDataFundbookDto
            {
                Identity = arg.Get("Identity"),
                FundBookName = arg.Get("FundBookName"),
                FundBookCurrencyCode = arg.Get("CurrencyCode"),
                ParentIdentity = arg.Get("ParentIdentity"),
                IsActive = true,
            };
        }

        public static TradingDataBenchmarkDto TradingDataBenchmarkDto(DataRow arg)
        {
            return new TradingDataBenchmarkDto
            {
                CurrencyIsoCode = arg.Get("CurrencyIsoCode"),
                SecurityName = arg.Get("Name"),
                Region = arg.Get("Region"),
                Sector = arg.Get("Sector"),
                Ticker = arg.Get("Ticker"),
                Ric = arg.Get("Ric"),
                CustomIdentity = string.Empty,
            };
        }

        public static TradingDataTradeDto TradingDataTradeDto(DataRow arg)
        {
            return new TradingDataTradeDto
            {
                Date = arg.Field<DateTime>("Date"),
                FundBookIdentity = arg.Get("FundBookIdentity"),
                Mic = arg.Get("Mic"),
                Isin = arg.Get("Isin"),
                Ric = arg.Get("Ric"),
                SecurityName = arg.Get("SecurityName"),
                Sedol = arg.Get("Sedol"),
                TradeQuantity = GetTradeQuantity(arg),
                TradePrice = ParseDecimal(arg["TradePrice"]) ?? 0,
                CurrencyCode = arg.Get("Currency"),
                FxRate = ParseDecimal(arg["FxRate"]) ?? 0,
                OriginalId = arg.Get("Identity"),
                SkipThisTrade = !TradeEntryTypes.Contains(arg["EntryTypeName"].ToString()),
                Status = string.Equals(arg["Status"].ToString(), "NEW", StringComparison.InvariantCultureIgnoreCase) ? TradeStatus.New :
                                                                              string.Equals(arg["Status"].ToString(), "AMEND", StringComparison.InvariantCultureIgnoreCase) ? TradeStatus.Update :
                                                                              string.Equals(arg["Status"].ToString(), "CANCEL", StringComparison.InvariantCultureIgnoreCase) ? TradeStatus.Cancel : TradeStatus.New,
                Cusip = string.Empty,
                CustomIdentity = string.Empty,
            };
        }

        public static TradingDataOriginalPositionDto TradingDataOriginalPositionDto(DataRow arg)
        {
            return new TradingDataOriginalPositionDto
            {
                Cusip = arg.Get("Cusip"),
                Date = arg.Field<DateTime>("Date"),
                FundBookIdentity = arg.Get("FundBookIdentity"),
                Isin = arg.Get("Isin"),
                Ric = arg.Get("Ric"),
                Sedol = arg.Get("Sedol"),
                StrategyIdentity = arg.Get("StrategyIdentity"),
                Quantity = ParseDecimal(arg["Quantity"]) ?? 0,
                Ticker = arg.Get("Ticker"),
                Exposure = null,
                TradePnL = 0,
                PositionPnL = ParseDecimal(arg["FundPnL"]) + ParseDecimal(arg["FundCarryPnL"]),

                CustomIdentity = string.Empty,
                Mic = string.Empty,
                SecurityName = string.Empty,
            };
        }

        public static TradingDataCapitalDto TradingDataCapitalDto(DataRow arg)
        {
            return new TradingDataCapitalDto
            {
                FundBookIdentity = arg.Get("Fundbook"),
                Date = arg.Field<DateTime>("Date"),
                CloseCapital = arg.Field<decimal>("CloseCapital"),
                OpenCapital = null,
            };
        }

        private static decimal GetTradeQuantity(DataRow src)
        {
            var entryType = src["EntryTypeName"].ToString();
            var tradeQuantityAsString = src["TradeQuantity"].ToString();
            var parsedTradeQuantity = decimal.Parse(tradeQuantityAsString);
            return SellTradeEntryTypes.Contains(entryType) ? -parsedTradeQuantity : parsedTradeQuantity;
        }

        private static decimal? ParseDecimal(object src)
        {
            if (src == null)
            {
                return null;
            }
            try
            {
                if (src is DBNull)
                {
                    return null;
                }
                if (src is decimal)
                {
                    return (decimal)src;
                }
                if (src is double)
                {
                    return (decimal)(double)src;
                }

                var s = src.ToString();
                s = s.Trim('"');
                s = s.Replace(",", "");

                return string.IsNullOrEmpty(s)
                    ? 0
                    : decimal.Parse(s, CultureInfo.InvariantCulture);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Canot parse '{0}' as decimal", src), ex);
            }
        }
    }
}
